package com.iwish.server.storage;

import java.io.UnsupportedEncodingException;  
import java.nio.ByteBuffer;  
import java.nio.ByteOrder;  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
import java.util.*;  

import org.apache.hadoop.util.hash.Hash;
import org.apache.log4j.Logger;

import com.iwish.server.storage.util.ConfigHelper;

import redis.clients.jedis.JedisPoolConfig;


  
/** 
 */  
public class CacheManager {  
    public  static TreeMap<Long,RedisPool> nodes = new TreeMap<Long,RedisPool>();  ;  
    private static List<Map> shards = new ArrayList();  
    private static int VIRTUAL_NUM = 10;  
    static Logger logger = Logger.getLogger(CacheManager.class);
    static ArrayList<RedisPool> poolShards =new  ArrayList();
    /** 
     * 锟斤拷始锟斤拷一锟铰伙拷 
     */  
    private static void initCacheNodes() {
    	for (int i = 0; i < 3; i++) {
    		
    		Map m2 = new HashMap(3);
    		m2.put("name","cache server mo"+i);
    		m2.put("ip",ConfigHelper.REDIS_HOST);
    		m2.put("port",ConfigHelper.REDIS_PORT);
    		shards.add(m2); 
    	
		}
    	logger.info("loading cache servers config...");
    	
		if (poolShards.size()==0){
			JedisPoolConfig config = new JedisPoolConfig();
			config.setMaxActive(ConfigHelper.MAX_REDIS_CONN);
			config.setTestOnBorrow(true);
			config.setMinEvictableIdleTimeMillis(60000L);
			   config.setTimeBetweenEvictionRunsMillis(30000L);
		        config.setNumTestsPerEvictionRun(-1);
			
			for (Map m : shards) {
				RedisPool t = new RedisPool(config,m.get("ip").toString() ,Integer.valueOf(m.get("port").toString()));
				t.setAlisa(m.get("ip").toString()+":"+m.get("port").toString()+m.get("name").toString()); 
				poolShards. add( t);
			}
			logger.info("Successfully built cache connection pools  ");
	}
//         shards.add("192.168.0.0-锟斤拷锟斤拷锟斤拷0");  
//         shards.add("192.168.0.1-锟斤拷锟斤拷锟斤拷1");  
//         shards.add("192.168.0.2-锟斤拷锟斤拷锟斤拷2");  
//         shards.add("192.168.0.3-锟斤拷锟斤拷锟斤拷3");  
//         shards.add("192.168.0.4-锟斤拷锟斤拷锟斤拷4");  
  
       
        for(int i=0; i<poolShards.size(); i++) {  
        	RedisPool pool = poolShards.get(i);  
            for(int j=0; j<VIRTUAL_NUM; j++) {  
                nodes.put(hash(computeMd5(("SHARD-" + i + "-VIRTUAL-" + j).getBytes()),j), pool);  
            }  
        } 
        logger.info("Successfully built cache hash treemap"+" made up of "+nodes.size()+" cache servers");
    }  
    
//    private void  initCachePool(){
//		if (poolShards==null){
//			JedisPoolConfig config = new JedisPoolConfig();
//			config.setTestOnBorrow(true);
//			config.setMinEvictableIdleTimeMillis(60000L);
//			   config.setTimeBetweenEvictionRunsMillis(30000L);
//		        config.setNumTestsPerEvictionRun(-1);
//			
//			for (Map m : shards) {
//				poolShards. add( new RedisPool(config,m.get("ip").toString() ,Integer.valueOf(m.get("port").toString())));
//			}
//	}
//		
//	}
//    hash.getShardInfo(hash.hash(hash.computeMd5(String.valueOf(i)),ran.nextInt(hash.VIRTUAL_NUM))
    		public  static Long getShardInfo(byte[] key2) {  
    		     if(nodes.size()==0)
    		     initCacheNodes();
//    	         Random ran = new Random();  
        Long key =CacheManager.hash(CacheManager.computeMd5(key2),0);
        if(nodes.containsKey(key))
        	 return key;
        
        SortedMap<Long, RedisPool> tailMap=nodes.tailMap(key);  
        if(tailMap.isEmpty()) {  
            key = nodes.firstKey();  
        } else {  
            key = tailMap.firstKey();  
        }  
        logger.info("Successfully choose cache node"+nodes.get(key).getAlisa());
        return key;  
    }  
    /** 
     * 锟斤拷锟絢ey锟斤拷hash值取锟矫凤拷锟斤拷锟斤拷锟节碉拷锟斤拷息 
     * @param hash 
     * @return 
     */  
     static Object getShardInfo(long hash) {  
        Long key = hash;  
        SortedMap<Long, RedisPool> tailMap=nodes.tailMap(key);  
        if(tailMap.isEmpty()) {  
            key = nodes.firstKey();  
        } else {  
            key = tailMap.firstKey();  
        }  
        return nodes.get(key);  
    }  
  
    /** 
     * 锟斤拷印圆锟斤拷锟节碉拷锟斤拷锟�
     */  
     public void printMap() {  
         System.out.println(nodes);  
     }  
  
    /** 
     * 锟斤拷锟�^32锟窖节碉拷植锟斤拷锟皆诧拷锟斤拷锟斤拷妗�
     * @param digest 
     * @param nTime 
     * @return 
     */  
      private long hash2(byte[] digest, int nTime) {  
        long rv = ((long) (digest[3+nTime*4] & 0xFF) << 24)  
                | ((long) (digest[2+nTime*4] & 0xFF) << 16)  
                | ((long) (digest[1+nTime*4] & 0xFF) << 8)  
                | (digest[0+nTime*4] & 0xFF);  
  
        return rv & 0xffffffffL; /* Truncate to 32-bits */  
      }  
      public static long hash(byte[] digest, int nTime) {  
        return Hash.getInstance(1).hash(digest);
        }  
  
    /** 
     * Get the md5 of the given key. 
     * 锟斤拷锟斤拷MD5值 
     */  
     private static byte[] computeMd5(byte[] k) {  
        MessageDigest md5;  
        try {  
            md5 = MessageDigest.getInstance("MD5");  
        } catch (NoSuchAlgorithmException e) {  
            throw new RuntimeException("MD5 not supported", e);  
        }  
        md5.reset();  
          
  
        md5.update(k);  
        return md5.digest();  
     }  
  
     public static void main(String[] args) {  
         Random ran = new Random();  
         if(nodes.size()==0)
		     initCacheNodes();
         int []rs = new int[5];
         
         //循锟斤拷50锟轿ｏ拷锟斤拷为锟斤拷取50锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷效锟斤拷然也锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟轿何碉拷锟斤拷锟斤拷锟斤拷锟斤拷锟� 
         for(int i=0; i<111150; i++) {
        	 int d = Integer.valueOf(CacheManager.getShardInfo(CacheManager.hash(CacheManager.computeMd5(String.valueOf(i).getBytes()),ran.nextInt(CacheManager.VIRTUAL_NUM))).toString().substring(10,11));
             rs[d]=rs[d]+1;  
         }  
         for (int i = 0; i < rs.length; i++) {
			System.out.println(rs[i]);
		}
   }  
  
}  